home *** CD-ROM | disk | FTP | other *** search
/ World of Video / World of Video.iso / datafiles / misc / hardware / 1541_to_amiga / 1541.c < prev    next >
C/C++ Source or Header  |  1995-02-13  |  14KB  |  399 lines

  1. ;/*
  2. sc DisAsm=ram:1541.s 1541.c ProgramName=1541 ObjectName=ram: Ignore=73+306 GST=include:all.gst GSTImm NoIcon NoStackCheck UnsignedChar Parm=Register Opt OptSched OptInLocal OptDep=100 OptRDep=100 CommentNest Link
  3. quit
  4. */
  5.  
  6. /*
  7. 1541 disk-to-file convertor for A1020
  8. Copyright © 1994 by Dan Babcock
  9.  
  10. Compiled with SAS/C V6.51
  11. */
  12.  
  13. typedef short bool; /* enum bool { FALSE, TRUE }; */
  14.  
  15. /* Buffers */
  16. #define RAWBUFSIZE 9000
  17. #define MAXBITPTR RAWBUFSIZE*8-400*8
  18.  
  19. #define DISKSIZE 683*256
  20. static __chip char RawBuffer[RAWBUFSIZE];
  21. static __far char DecodedBuffer[DISKSIZE];
  22.  
  23. /* Command line parsing */
  24. enum cmdargs { DRIVE, FILENAME, RETRY, TOP, OFFSET, NUMARGS };
  25. static struct RDArgs *rdargs;
  26. static LONG args[NUMARGS];
  27.  
  28. /* Device access */
  29. static struct MsgPort *port;
  30. static struct IOStdReq *io;
  31. static bool DevOpen;
  32.  
  33. /* Misc */
  34. static char ver[]="$VER: 1541 1.01 (17.6.94)\n";
  35. long __OSlibversion = 37;
  36. struct Library *DiskBase;
  37. static unsigned RetryCount=10;
  38.  
  39. /* Finish disk I/O */
  40. static void FinishIO(void)
  41. {
  42.     io->io_Command = TD_MOTOR;
  43.     io->io_Length = 0;
  44.     DoIO((struct IORequest *)io);
  45. }
  46.  
  47. /* Autotermination routine */
  48. void _STDautoterm(void)
  49. {
  50.     /* Free misc */
  51.     if (DevOpen) {
  52.         FinishIO();
  53.         CloseDevice((struct IORequest *)io);
  54.     }
  55.     if (io) DeleteIORequest(io);
  56.     if (port) DeleteMsgPort(port);
  57.     if (rdargs) FreeArgs(rdargs);
  58. }
  59.  
  60. /* Read a raw track */
  61. /* Unfortunately we can't use TD_RAWREAD, since we need to set 4us/bit mode */
  62. static void RawRead(unsigned track)
  63. {
  64.     static struct DiscResourceUnit diskunit; /* initialized to zero because of static */
  65. //    volatile struct CIA *ciaa=(void*)0xbfe001;
  66.     volatile struct CIA *ciab=(void*)0xbfd000;
  67.     volatile struct Custom *custom=(void*)0xdff000;
  68.  
  69.     /* TD motor on */
  70.     io->io_Command = TD_MOTOR;
  71.     io->io_Length = 1;
  72.     DoIO((struct IORequest *)io);
  73.  
  74.     /* Seek to the proper track */
  75.     io->io_Command = TD_SEEK;
  76.     io->io_Offset = track*5632;
  77.     if (args[OFFSET])
  78.         io->io_Offset += (*(int*)args[OFFSET])*11264;
  79.     if (io->io_Offset > 11264*39)
  80.         io->io_Offset = 0;
  81.     DoIO((struct IORequest *)io);
  82.  
  83.     /* Take over the disk hardware and read the track "by hand" */
  84.     /* (which is a pain even when taking some shortcuts) */
  85.     /* Here goes...*/
  86.  
  87.     /* get the resource */
  88.     diskunit.dru_Message.mn_ReplyPort=port;
  89.     diskunit.dru_Message.mn_Node.ln_Name="1541 disk reader";
  90.     while (!GetUnit((struct DiskResourceUnit*)&diskunit)) {
  91.         WaitPort(port);
  92.         GetMsg(port); /* important! remove message */
  93.     }
  94.  
  95.     /* set up CIA bits, turn on motor, wait for motor */
  96.     ciab->ciaprb |= CIAF_DSKSEL0|CIAF_DSKSEL1|CIAF_DSKSEL2|CIAF_DSKSEL3;
  97.     ciab->ciaprb &= ~CIAF_DSKMOTOR;
  98.     ciab->ciaprb &= ~(1<<(*(int *)args[DRIVE]+3));
  99.     if (track & 1)
  100.         ciab->ciaprb &= ~CIAF_DSKSIDE;
  101.     else
  102.         ciab->ciaprb |= CIAF_DSKSIDE;
  103. //    while (ciaa->ciapra & CIAF_DSKRDY)
  104. //        ;
  105.  
  106.     /* set up disk hardware */
  107.     custom->adkcon = ADKF_WORDSYNC|ADKF_MSBSYNC|ADKF_FAST;
  108.     custom->intreq = INTF_DSKBLK;
  109.     custom->dskpt = RawBuffer;
  110.  
  111.     /* now for the main event...drum roll please */
  112.     custom->dsklen = (RAWBUFSIZE/2)|(1<<15);
  113.     custom->dsklen = (RAWBUFSIZE/2)|(1<<15);
  114.     while (!(custom->intreqr & INTF_DSKBLK))
  115.         ;
  116.  
  117.     /* done! */
  118.     custom->intreq = INTF_DSKBLK;
  119.     custom->dsklen = DSKDMAOFF;
  120.     GiveUnit();
  121. }
  122.  
  123.  
  124. static unsigned bitptr;    /* Bit pointer to raw data (offset from RawBuffer) */
  125.  
  126. /* Grab 10 bits of GCR from RawBuffer+bitptr and return a byte of decoded data */
  127. /* Note: No checking for "end of buffer" condition! */
  128.  
  129. static __inline UBYTE GetByte(void)
  130. {
  131.     static UBYTE GCRTable[] = {
  132.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  133.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  134.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  135.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  136.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  137.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  138.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  139.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  140.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  141.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  142.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  143.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  144.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  145.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  146.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  147.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  148.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  149.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  150.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x80,0x81,0x00,0x8C,0x84,0x85,
  151.         0x00,0x00,0x82,0x83,0x00,0x8F,0x86,0x87,0x00,0x89,0x8A,0x8B,0x00,0x8D,0x8E,0x00,
  152.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0x00,0x0C,0x04,0x05,
  153.         0x00,0x00,0x02,0x03,0x00,0x0F,0x06,0x07,0x00,0x09,0x0A,0x0B,0x00,0x0D,0x0E,0x00,
  154.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x10,0x11,0x00,0x1C,0x14,0x15,
  155.         0x00,0x00,0x12,0x13,0x00,0x1F,0x16,0x17,0x00,0x19,0x1A,0x1B,0x00,0x1D,0x1E,0x00,
  156.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  157.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  158.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0xC0,0xC1,0x00,0xCC,0xC4,0xC5,
  159.         0x00,0x00,0xC2,0xC3,0x00,0xCF,0xC6,0xC7,0x00,0xC9,0xCA,0xCB,0x00,0xCD,0xCE,0x00,
  160.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x40,0x41,0x00,0x4C,0x44,0x45,
  161.         0x00,0x00,0x42,0x43,0x00,0x4F,0x46,0x47,0x00,0x49,0x4A,0x4B,0x00,0x4D,0x4E,0x00,
  162.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x50,0x51,0x00,0x5C,0x54,0x55,
  163.         0x00,0x00,0x52,0x53,0x00,0x5F,0x56,0x57,0x00,0x59,0x5A,0x5B,0x00,0x5D,0x5E,0x00,
  164.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  165.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  166.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  167.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  168.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x20,0x21,0x00,0x2C,0x24,0x25,
  169.         0x00,0x00,0x22,0x23,0x00,0x2F,0x26,0x27,0x00,0x29,0x2A,0x2B,0x00,0x2D,0x2E,0x00,
  170.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x30,0x31,0x00,0x3C,0x34,0x35,
  171.         0x00,0x00,0x32,0x33,0x00,0x3F,0x36,0x37,0x00,0x39,0x3A,0x3B,0x00,0x3D,0x3E,0x00,
  172.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  173.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  174.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xF0,0xF1,0x00,0xFC,0xF4,0xF5,
  175.         0x00,0x00,0xF2,0xF3,0x00,0xFF,0xF6,0xF7,0x00,0xF9,0xFA,0xFB,0x00,0xFD,0xFE,0x00,
  176.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x60,0x61,0x00,0x6C,0x64,0x65,
  177.         0x00,0x00,0x62,0x63,0x00,0x6F,0x66,0x67,0x00,0x69,0x6A,0x6B,0x00,0x6D,0x6E,0x00,
  178.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x70,0x71,0x00,0x7C,0x74,0x75,
  179.         0x00,0x00,0x72,0x73,0x00,0x7F,0x76,0x77,0x00,0x79,0x7A,0x7B,0x00,0x7D,0x7E,0x00,
  180.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  181.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  182.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x90,0x91,0x00,0x9C,0x94,0x95,
  183.         0x00,0x00,0x92,0x93,0x00,0x9F,0x96,0x97,0x00,0x99,0x9A,0x9B,0x00,0x9D,0x9E,0x00,
  184.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xA0,0xA1,0x00,0xAC,0xA4,0xA5,
  185.         0x00,0x00,0xA2,0xA3,0x00,0xAF,0xA6,0xA7,0x00,0xA9,0xAA,0xAB,0x00,0xAD,0xAE,0x00,
  186.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB8,0xB0,0xB1,0x00,0xBC,0xB4,0xB5,
  187.         0x00,0x00,0xB2,0xB3,0x00,0xBF,0xB6,0xB7,0x00,0xB9,0xBA,0xBB,0x00,0xBD,0xBE,0x00,
  188.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  189.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  190.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0xD0,0xD1,0x00,0xDC,0xD4,0xD5,
  191.         0x00,0x00,0xD2,0xD3,0x00,0xDF,0xD6,0xD7,0x00,0xD9,0xDA,0xDB,0x00,0xDD,0xDE,0x00,
  192.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0xE0,0xE1,0x00,0xEC,0xE4,0xE5,
  193.         0x00,0x00,0xE2,0xE3,0x00,0xEF,0xE6,0xE7,0x00,0xE9,0xEA,0xEB,0x00,0xED,0xEE,0x00,
  194.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  195.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  196.     };
  197.  
  198.     ULONG data;
  199.  
  200.     /* Fetch a longword at a word address using bitptr */
  201.     data=*(ULONG*)(RawBuffer+(bitptr>>3 & ~1));
  202.  
  203.     /* Right-adjust and mask */
  204.     data >>= 22-(bitptr & 15);
  205.     data &= 1023;
  206.  
  207.     bitptr += 10;
  208.     return GCRTable[data];
  209. }
  210.  
  211. /* Scan for sync mark from bitptr. Returns TRUE if sync found.
  212.    We look for 9 1-bits (minimum to distinguish from normal data) starting on a byte
  213.    alignment. Consequently there must be at least 16 1-bits physically on the disk.
  214. */
  215. static bool ScanSync(void)
  216. {
  217.     UBYTE *ptr;
  218.     unsigned offset;
  219.  
  220.     ptr=RawBuffer+(bitptr>>3);
  221.     if (bitptr&7) ptr++;
  222.     if (ptr >= RawBuffer+RAWBUFSIZE) return FALSE;
  223.  
  224.     while (1) {
  225.         while (*ptr != 0xFF) {
  226.             ++ptr;
  227.             if (ptr >= RawBuffer+RAWBUFSIZE) return FALSE;
  228.         }
  229.         ++ptr;
  230.         if (ptr >= RawBuffer+RAWBUFSIZE) return FALSE;
  231.         if (*ptr & 0x80) break;
  232.     }
  233.     while (*ptr == 0xFF) {
  234.         ++ptr;
  235.         if (ptr >= RawBuffer+RAWBUFSIZE) return FALSE;
  236.     }
  237.  
  238.     if (*ptr == 0xFE) offset=7;
  239.     else if ((*ptr&0xFC)==0xFC) offset=6;
  240.     else if ((*ptr&0xF8)==0xF8) offset=5;
  241.     else if ((*ptr&0xF0)==0xF0) offset=4;
  242.     else if ((*ptr&0xE0)==0xE0) offset=3;
  243.     else if ((*ptr&0xC0)==0xC0) offset=2;
  244.     else if ((*ptr&0x80)==0x80) offset=1;
  245.     else offset=0;
  246.  
  247.     bitptr=(ptr-RawBuffer)*8 + offset;
  248.     return TRUE;
  249. }
  250.  
  251. static void ReadAndDecodeTrack(unsigned track, char *DecodedBuffer)
  252. {
  253.     unsigned NeedMap, ReadMap;
  254.     unsigned drivetrack;    /* 1541 track# */
  255.     unsigned SectorsPerTrack;
  256.     int retry;
  257.     UBYTE *secptr;
  258.  
  259.     unsigned sec;
  260.     ULONG *longsecptr;
  261.  
  262.     drivetrack=track/2 + 1;
  263.     /* Set bufbase, SectorsPerTrack, and DecodedBuffer */
  264.     if (drivetrack < 18) {    /* zone 1 */
  265.         SectorsPerTrack=21; DecodedBuffer+=(drivetrack-1)*21*256; NeedMap=(1<<21)-1;
  266.     }
  267.     else if (drivetrack < 25) {    /* zone 2 */
  268.         SectorsPerTrack=19; DecodedBuffer+=357*256+(drivetrack-18)*19*256; NeedMap=(1<<19)-1;
  269.     }
  270.     else if (drivetrack < 31) {    /* zone 3 */
  271.         SectorsPerTrack=18; DecodedBuffer+=490*256+(drivetrack-25)*18*256; NeedMap=(1<<18)-1;
  272.     }
  273.     else {    /* zone 4 */
  274.         SectorsPerTrack=17; DecodedBuffer+=598*256+(drivetrack-31)*17*256; NeedMap=(1<<17)-1;
  275.     }
  276.  
  277.     ReadMap=0;
  278.     for (retry=RetryCount; (ReadMap != NeedMap) && (retry>=0); retry--) {
  279.         bitptr=0;
  280.         RawRead(track);
  281.         while (ReadMap != NeedMap) {
  282.             /* decode sector */
  283.             UBYTE checksum, sectornum, tracknum, id1, id2;
  284.             unsigned i;
  285.  
  286.             if (!ScanSync()) break;
  287.             if (bitptr > MAXBITPTR) break;
  288.             if (GetByte() != 0x08) continue; /* if not header, restart */
  289.             checksum=GetByte(); sectornum=GetByte(); tracknum=GetByte(); id1=GetByte(); id2=GetByte();
  290.             if (checksum^tracknum^sectornum^id1^id2) continue;
  291.             if (sectornum >= SectorsPerTrack) {
  292.                 printf("Sector number out of range on track %d\n",drivetrack);
  293.                 continue;
  294.             }
  295.             if (tracknum != drivetrack) {
  296.                 printf("Wrong track number (%d) on track %d\n",(int)tracknum,drivetrack);
  297.                 continue;
  298.             }
  299.             if (ReadMap & (1<<sectornum)) continue; /* already read 'em */
  300.  
  301.             /* Header looks good. Onto the data block. */
  302.             if (!ScanSync()) break;
  303.             if (bitptr > MAXBITPTR) break;
  304.             if (GetByte() != 0x07) continue; /* if not data block, restart */
  305.             secptr=DecodedBuffer+(sectornum*256);
  306.             checksum=0;
  307.             for (i=0; i <= 255; i++) {
  308.                 *secptr=GetByte(); checksum ^= *secptr; secptr++;
  309.             }
  310.             if (GetByte() == checksum) {
  311.                 ReadMap |= 1<<sectornum;
  312.             }
  313.         }
  314.         if (ReadMap != NeedMap) {
  315.             printf("Trouble reading track %d\n",drivetrack);
  316.         }
  317.     }
  318.     if (ReadMap == NeedMap) {
  319. //        printf("Track %d read successfully\n",drivetrack);
  320.         return;
  321.     }
  322.  
  323.     /* We couldn't read one or more sectors on this track. Print out some info and
  324.        mark the bad sectors with a special identifier */
  325.     printf("Bad sectors on track %d: ",drivetrack);
  326.     for (sec=0; sec < SectorsPerTrack; sec++) {
  327.         unsigned i;
  328.         if (!(ReadMap & 1<<sec)) {
  329.             printf("%d, ",sec);
  330.             secptr=DecodedBuffer+(sec*256);
  331.             longsecptr=(ULONG*)secptr;
  332.             for (i=0; i <= 63; i++) {
  333.                 longsecptr[i]=0;
  334.             }
  335.             secptr[1]=0xFF;
  336.             strcpy(secptr+2,"LAZARUS");
  337.         }
  338.     }
  339.     printf("\b\b  \n");
  340. }
  341.  
  342.  
  343. /* Returns TRUE if successful */
  344. static bool WriteFile(char *filename, char *buffer, unsigned size)
  345. {
  346.     BPTR file;
  347.     LONG actual;
  348.  
  349.     file=Open(filename,MODE_NEWFILE); if (!file) return FALSE;
  350.     actual=Write(file,buffer,size);
  351.     Close(file);
  352.     if (actual != size) return FALSE;
  353.     return TRUE;
  354. }
  355.  
  356. void main(void)
  357. {
  358.     unsigned track;
  359.  
  360.     printf("1541 - Copyright © 1994 by Dan Babcock\n");
  361.  
  362.     /* Handle command-line arguments */
  363.     rdargs=ReadArgs("DRIVE/N/A,FILENAME/A,RETRY/K/N,TOP/S,OFFSET/K/N",args,0);
  364.     if (rdargs == 0) {
  365.         printf("Invalid parameters\n");
  366.         return;
  367.     }
  368.     if (args[RETRY]) RetryCount=*(unsigned*)args[RETRY];
  369.  
  370.     /* Set up for trackdisk I/O */
  371.     DiskBase=OpenResource("disk.resource");
  372.     if ((port = CreateMsgPort())==0) {
  373.         printf("Could not create message port (out of memory)\n");
  374.         return;
  375.     }
  376.     if ((io = CreateIORequest(port,sizeof(struct IOStdReq)))==0) {
  377.         printf("Could not create IORequest (out of memory)\n");
  378.         return;
  379.     }
  380.     if (OpenDevice("trackdisk.device", *(int *)args[DRIVE], (struct IORequest *)io, TDF_ALLOW_NON_3_5)) {
  381.         printf("Could not open trackdisk unit %d\n",*(int *)args[DRIVE]);
  382.         return;
  383.     }
  384.     DevOpen = TRUE;
  385.  
  386.     /* Read and decode */
  387.     if (!args[TOP])
  388.         for (track=0; track <= 68; track+=2)
  389.             ReadAndDecodeTrack(track, DecodedBuffer);
  390.     else
  391.         for (track=1; track <= 69; track+=2)
  392.             ReadAndDecodeTrack(track, DecodedBuffer);
  393.  
  394.     /* Write image to file */
  395.     if (!WriteFile((char *)args[FILENAME],DecodedBuffer,DISKSIZE)) {
  396.         printf("Error writing image file\n");
  397.     }
  398. }
  399.